package com.roma.gcal.upload;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.extensions.When;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

public class GCalReport {
	// The base URL for a user's calendar metafeed (needs a username appended).
	private static final String METAFEED_URL_BASE = "http://www.google.com/calendar/feeds/";

	// The string to add to the user's metafeedUrl to access the owncalendars feed.
	private static final String OWNCALENDARS_FEED_URL_SUFFIX = "/owncalendars/full";

	// The URL for the owncalendars feed of the specified user.
	// (e.g.http://www.googe.com/feeds/calendar/jdoe@gmail.com/owncalendars/full)
	private static URL owncalendarsFeedUrl = null;

	final SimpleDateFormat GOOGLE_DT_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ");	//yyyy-MM-dd'T'HH:mm:ss
	final SimpleDateFormat SIMPLE_DT_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
	
	/**
	 * Utility classes should not have a public or default constructor.
	 */
	public GCalReport() {
	}

	private void printUserCalendars(String calURL, CalendarService service) throws IOException, ServiceException {
		URL myFeedURL = new URL(calURL);
		//CalendarEventFeed myFeed = service.getFeed(myFeedURL, CalendarEventFeed.class);
		CalendarEventFeed myFeed = service.getFeed(getCurentWeekQueryObj(myFeedURL), CalendarEventFeed.class);
		for (CalendarEventEntry eEntry : myFeed.getEntries()) {
			for (When time : eEntry.getTimes()) {
				//System.out.println(time.getStartTime() + " - " + time.getEndTime());
				long diff = time.getEndTime().getValue() - time.getStartTime().getValue();
				Date javaDt = new Date(time.getEndTime().getValue());
				System.out.println(eEntry.getTitle().getPlainText() + ", " + SIMPLE_DT_FORMAT.format(javaDt) + ", " + diff / (60 * 60 * 1000));
			}
		}
		return;
	}

	private String findUserCalendarURL(String calendarName, CalendarService service) throws IOException, ServiceException {
		// Send the request and receive the response:
		CalendarFeed resultFeed = service.getFeed(owncalendarsFeedUrl, CalendarFeed.class);

		// Print the title of each calendar
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			CalendarEntry entry = resultFeed.getEntries().get(i);
			String calEntryName = entry.getTitle().getPlainText();
			if (!calendarName.equalsIgnoreCase(calEntryName))
				continue;
//			System.out.println("\t" + entry.getTitle().getPlainText() + ", " + entry.getId());
//			System.out.println(entry.getLinks().get(0).getHref());
			String retURL = entry.getLinks().get(0).getHref();
			return retURL;
		}
		return null;
	}
	
	private DateTime getGoogleDateTime(Calendar calDT) {
		String strFormat = GOOGLE_DT_FORMAT.format(calDT.getTime());
		System.out.println(strFormat);
		String modStr = strFormat.substring(0, strFormat.length()-2) + ":00";
		System.out.println(modStr);
		DateTime gCalDTTime = DateTime.parseDateTime(modStr);
		//gCalDTTime.setTzShift(TimeZone.getTimeZone("America/New_York").getRawOffset()/144000000);
		return gCalDTTime;
	}

	private CalendarQuery getCalendarQuery(URL myFeedURL, Calendar startDT, Calendar endDT) {
		CalendarQuery myQuery = new CalendarQuery(myFeedURL);
		DateTime startDTTime = getGoogleDateTime(startDT);
		DateTime endDTTime = getGoogleDateTime(endDT);
//		When time = new When();
//		time.setStartTime(startDTTime);
//		time.setEndTime(endDTTime);
		myQuery.setMinimumStartTime(startDTTime);
		myQuery.setMaximumStartTime(endDTTime);
		return myQuery;
	}

	private CalendarQuery getCurentWeekQueryObj(URL myFeedURL) {
		Calendar now = getCurrentTime();
		int dayOfWeek = now.get(Calendar.DAY_OF_WEEK);
		if(dayOfWeek == 7) //if it is the begining
			dayOfWeek = 0;
		
		Calendar startDT = Calendar.getInstance();
		startDT.add(Calendar.DAY_OF_MONTH, (-1*dayOfWeek));
		
		Calendar endDT = Calendar.getInstance();
		endDT.add(Calendar.DAY_OF_MONTH, (7 - dayOfWeek - 1));

		CalendarQuery myQuery = getCalendarQuery(myFeedURL, startDT, endDT);
		return myQuery;
	}

	private Calendar getCurrentTime() {
		Calendar calDT = null;
		calDT = Calendar.getInstance();
//		calDT.setTime(new Date());
		DateTime gCalTime = DateTime.now();
		calDT.setTimeInMillis(gCalTime.getValue());
		return calDT;
	}
	private Calendar getTodayDayStartDTObject(boolean useCurrentTime) {
		Calendar startDT = getCurrentTime();
		if(!useCurrentTime)
			startDT.set(Calendar.HOUR_OF_DAY, 0);
		return startDT;
	}
	
	private Calendar getTodayDayEndDTObject(boolean useCurrentTime) {
		Calendar endDT = getCurrentTime();
		if(!useCurrentTime) {
			//endDT.add(Calendar.DAY_OF_MONTH, 1);
			endDT.set(Calendar.HOUR_OF_DAY, 23);
		}
		return endDT;
	}

	private CalendarEventEntry findToDayCalObj(URL myFeedURL, CalendarService service) {
		CalendarEventEntry eEntry = null;
		try {
			Calendar startDT = getTodayDayStartDTObject(false);
			Calendar endDT = getTodayDayEndDTObject(false);

			CalendarQuery calQuery = getCalendarQuery(myFeedURL, startDT, endDT);
			CalendarEventFeed myFeed = service.getFeed(calQuery, CalendarEventFeed.class);
			if(myFeed != null) {
				for(CalendarEventEntry tEvent : myFeed.getEntries()) {
					eEntry = tEvent;
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return eEntry;
	}
	
	private CalendarEventEntry addCalendar2GCal(String calURL, CalendarService service) throws IOException, ServiceException {
		System.out.println("Creating a secondary calendar");

		URL myFeedURL = new URL(calURL);
		CalendarEventEntry calendar = null;
//		// first find the existing one..
//		calendar = findToDayCalObj(myFeedURL, service);
//		// Create the calendar
//		if(calendar == null)
			calendar = new CalendarEventEntry();
		calendar.setTitle(new PlainTextConstruct("USCIS:Sapient"));

		Calendar startDT = null;
		Calendar endDT = null;
		startDT = getTodayDayStartDTObject(true);	//create always with current time
		endDT = getTodayDayEndDTObject(false);

		calendar.setSummary(new PlainTextConstruct("USCIS program design and development"));
		DateTime startTime = DateTime.now();	//getGoogleDateTime(startDT);
		DateTime endTime = getGoogleDateTime(endDT);

//		DateTime startTime = DateTime.parseDateTime("2011-04-29T09:00:00");
//		DateTime endTime = DateTime.parseDateTime("2011-04-29T18:00:00");
		When eventTimes = new When();
		eventTimes.setStartTime(startTime);
		eventTimes.setEndTime(endTime);

		System.out.println(GOOGLE_DT_FORMAT.format(eventTimes.getStartTime().getValue()) + " : " + GOOGLE_DT_FORMAT.format(eventTimes.getEndTime().getValue()));
		
		calendar.addTime(eventTimes);
		// Insert the calendar
		return service.insert(myFeedURL, calendar);
	}

	private CalendarEventEntry updateCalendarGCal(String calURL, CalendarService service) throws IOException, ServiceException {
		System.out.println("Updating a secondary calendar");

		URL myFeedURL = new URL(calURL);
		// first find the existing one..
		CalendarEventEntry calendar = findToDayCalObj(myFeedURL, service);
		// Create the calendar
		if(calendar == null) {
			System.out.println("Can't find Calender object for today in Google, trying creating one first.");
			return null;
		}
		Calendar startDT = null;
		Calendar endDT = getTodayDayEndDTObject(true);
		
		List<When> times = calendar.getTimes();
		if(times == null || times.size() == 0) {
			System.out.println("Can't find Time Objects in today's Calender object in Google, try recreating another one.");
			return null;
		} 
		
		When time = null;
		time = times.get(times.size() - 1);			

		System.out.println(GOOGLE_DT_FORMAT.format(time.getStartTime().getValue()) + " : " + GOOGLE_DT_FORMAT.format(time.getEndTime().getValue()) );

		DateTime endTime = DateTime.now();	//DateTime.parseDateTime(GOOGLE_DT_FORMAT.format(endDT.getTime()));
		time.setEndTime(endTime);

		System.out.println(GOOGLE_DT_FORMAT.format(time.getStartTime().getValue()) + " : " + GOOGLE_DT_FORMAT.format(time.getEndTime().getValue()) );
		
		// Update the calendar
		return service.update(myFeedURL, calendar);
	}

	public static void main(String[] args) {
		String userName = "rcingh@gmail.com";
		String userPassword = "poornima";
		String calendarName = "TImesheets";
		
		GCalReport report = new GCalReport();
		int option = report.getOption();
		if(option == -1)
			return;
		System.out.println("Option is : " + option);
		
		// Create necessary URL objects
		try {
			owncalendarsFeedUrl = new URL(METAFEED_URL_BASE + userName + OWNCALENDARS_FEED_URL_SUFFIX);
		} catch (MalformedURLException e) {
			// Bad URL
			System.err.println("Uh oh - you've got an invalid URL.");
			e.printStackTrace();
			return;
		}

		// Create CalendarService and authenticate using ClientLogin
		CalendarService service = new CalendarService(calendarName + "Feed");

		try {
			service.setUserCredentials(userName, userPassword);
		} catch (AuthenticationException e) {
			// Invalid credentials
			e.printStackTrace();
		}

		// Demonstrate retrieving various calendar feeds.
		try {
			System.out.println("Calendars in owncalendars feed");
			String calURL = report.findUserCalendarURL(calendarName, service);
			if(calURL == null)
				return;
			
			//report.printUserCalendars(calURL, service);
			//report.createCalendar(calURL, service);
			if(option == 1)
				report.addCalendar2GCal(calURL, service);
			else if (option == 2)
				report.updateCalendarGCal(calURL, service);
			else if (option == 3)
				report.printUserCalendars(calURL, service);
		} catch (IOException e) {
			// Communications error
			System.err.println("There was a problem communicating with the service.");
			e.printStackTrace();
		} catch (ServiceException e) {
			// Server side error
			System.err.println("The server had a problem handling your request.");
			e.printStackTrace();
		}
	}
	
	public int getOption() {
		int retValue = -1;
		try {
			//  open up standard input
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("Enter your option: ");
			System.out.println("\t\t1. Start Timer: ");
			System.out.println("\t\t2. End Timer: ");
			System.out.println("\t\t3. Report Week: ");
			retValue = Integer.parseInt(br.readLine());
		} catch(Exception e) {
			e.printStackTrace();
		}
		return retValue;
	}
}
